package yartiss.engine.simulation;

import yartiss.engine.simulation.events.EventGenerator;
import yartiss.engine.simulation.system.ITaskSet;

public class Scheduler {

	private long previousDate;
	private final EventGenerator eventGenerator;
	private Processor [] processors = new Processor[]{new Processor(1, 20, 20)};
	
	public Scheduler(EventGenerator eventGenerator){
		this.eventGenerator = eventGenerator;
	}
	
	/**
	 * @return the processors
	 */
	public Processor [] getProcessors() {
		return processors;
	}

	/**
	 * @param processors the processors to set
	 */
	public void setProcessors(Processor [] processors) {
		this.processors = processors;
	}

	
	public void schedule(Event event, ITaskSet taskSet, ISchedulingPolicy policy, IEnergyProfile energyProfile, long date, boolean isEnergyAware){

		long elapsedTime = event.getDate() - previousDate;
		long consumed = 0;

		assert elapsedTime >= 0 : "back to the future";

		for (Processor proc : processors) {
			if (proc.getCurrentTask() != null /* && elapsedTime>0 */ )
				consumed += proc.execute(elapsedTime, energyProfile);
		}
		energyProfile.updateEnergy(elapsedTime, consumed, date);
		
		replaceCurrentTask(event, taskSet, policy, energyProfile,  date);
		
		previousDate = event.getDate();
		long currentEnergyLevel = energyProfile.getCurrentEnergyLevel();
		event.setMetric(Event.EnergyLevel, currentEnergyLevel);
		
		if(isEnergyAware && currentEnergyLevel < energyProfile.getMinEnergyLevel()){
			eventGenerator.generateEvent("energy_failure",0, event.getTask(), date, null);
			System.out.println("... mort ....");
		}
	}

	private void replaceCurrentTask(Event event, ITaskSet taskSet, ISchedulingPolicy policy,  IEnergyProfile energyProfile,  long date) {

		policy.chooseNextTasks(processors, taskSet, energyProfile, date,eventGenerator);

		event.setMetrics(policy.getMetrics());
		
		boolean [] lastExecutedJobHasCompleted = new boolean [processors.length];
		boolean [] equals =  new boolean [processors.length];
		
		for (int i = 0; i < processors.length; i++) {
			if(processors[i].getCurrentTask() != null){
				lastExecutedJobHasCompleted[i] = processors[i].getCurrentTask().lastExecutedJobHasCompleted();
				equals[i] = processors[i].getCurrentTask().equals(processors[i].getNextTask());
			}
			if (processors[i].getCurrentTask() != null	&& (!equals[i] || lastExecutedJobHasCompleted[i])){
				eventGenerator.generateEvent("job_execution_end",processors[i].getId(), processors[i].getCurrentTask(), date, null);
				long  checkMaxReached = (energyProfile.getMaxEnergyLevel() - energyProfile.getCurrentEnergyLevel()) / energyProfile.getPowerRate() ;  
				eventGenerator.generateEvent("check_energy_state", processors[i].getId(), processors[i].getCurrentTask(), date + checkMaxReached, null);
			}

			lastExecutedJobHasCompleted[i] = false; 
			equals[i] = false;
			if(processors[i].getNextTask() != null){
				lastExecutedJobHasCompleted[i] = processors[i].getNextTask().lastExecutedJobHasCompleted();
				equals[i] = processors[i].getNextTask().equals(processors[i].getCurrentTask());
			}
			if (processors[i].getNextTask() != null && (!equals[i] || lastExecutedJobHasCompleted[i])) {	
				
				eventGenerator.generateEvent("job_execution_begin",processors[i].getId(), processors[i].getNextTask(), date, null);
				eventGenerator.generateEvent("check_completion" ,processors[i].getId(), processors[i].getNextTask(), date + processors[i].getNextTask().getRemainingCost(), null);
			}
			processors[i].setCurrentTask(processors[i].getNextTask());
		}
		
	}

	
	
}
